package com.braincookie.plugins.jira.tabpanels.fragments;

import com.atlassian.crowd.embedded.api.User;
import com.atlassian.jira.bc.issue.search.SearchService;
import com.atlassian.jira.config.ConstantsManager;
import com.atlassian.jira.config.properties.ApplicationProperties;
import com.atlassian.jira.issue.IssueFieldConstants;
import com.atlassian.jira.issue.customfields.option.Option;
import com.atlassian.jira.issue.fields.CustomField;
import com.atlassian.jira.issue.priority.Priority;
import com.atlassian.jira.issue.search.SearchException;
import com.atlassian.jira.issue.search.SearchRequest;
import com.atlassian.jira.issue.statistics.FilterStatisticsValuesGenerator;
import com.atlassian.jira.jql.builder.JqlClauseBuilder;
import com.atlassian.jira.jql.builder.JqlOrderByBuilder;
import com.atlassian.jira.jql.builder.JqlQueryBuilder;
import com.atlassian.jira.project.browse.BrowseContext;
import com.atlassian.jira.security.JiraAuthenticationContext;
import com.atlassian.jira.template.VelocityTemplatingEngine;
import com.atlassian.jira.util.VelocityParamFactory;
import com.atlassian.jira.util.velocity.VelocityRequestContext;
import com.atlassian.jira.util.velocity.VelocityRequestContextFactory;
import com.atlassian.jira.web.FieldVisibilityManager;
import com.atlassian.jira.web.bean.StatisticAccessorBean;
import com.atlassian.jira.web.bean.StatisticMapWrapper;
import com.atlassian.query.clause.Clause;
import com.atlassian.query.order.OrderBy;
import com.atlassian.query.order.SortOrder;
import com.braincookie.plugins.jira.tabpanels.utils.AbstractFilterUrlFragmentUtil;

import org.apache.log4j.Logger;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * Displays a breakdown of all the unresolved issues in the instance, grouped by priority.
 *
 * @since v4.0
 */
public class FilterUnresolvedIssuesByCustomFragment extends AbstractFilterUnresolvedIssuesFragment implements FilterTabPanelFragment
{
    private static final Logger log = Logger.getLogger(FilterUnresolvedIssuesByCustomFragment.class);

    private final ApplicationProperties applicationProperties;
    private final ConstantsManager constantsManager;
    private final VelocityRequestContextFactory velocityContextFactory;
    private final SearchService searchService;
    private final String customField;
    private final String title;

    public FilterUnresolvedIssuesByCustomFragment(final VelocityTemplatingEngine templatingEngine,
    		final VelocityParamFactory velocityFactory,
            final ApplicationProperties applicationProperties, final JiraAuthenticationContext authenticationContext,
            final FieldVisibilityManager fieldManager,
            final ConstantsManager constantsManager,
            final VelocityRequestContextFactory velocityContextFactory,
            final SearchService searchService,
            final String title,
            final String customField)
    {
        super(templatingEngine, velocityFactory, authenticationContext, fieldManager);
        this.applicationProperties = applicationProperties;
        this.constantsManager = constantsManager;
        this.velocityContextFactory = velocityContextFactory;
        this.searchService = searchService;
        this.title = title;
        this.customField = customField;
    }

    // NOTE: We need to ensure that all IDs are unique (as required by HTML specification).
    // When implementing ProjectTabPanelFragment ensure you add it to TestProjectTabPanelFragment test!
    public String getId()
    {
        return "unresolvedissuesbycustom";
    }

    String getIssueFieldConstant()
    {
        return "Custom";
    }

    protected Map<String, Object> createVelocityParams(final BrowseContext ctx)
    {
        final Map<String, Object> velocityParams = super.createVelocityParams(ctx);
        velocityParams.put("custom", getCustom(ctx));
        velocityParams.put("title", title);
        velocityParams.put("urlUtil", new OptionUrlUtil(getSearchRequest(ctx), authenticationContext.getLoggedInUser(), applicationProperties, velocityContextFactory, searchService));
        return velocityParams;
    }

    StatisticMapWrapper getCustom(final BrowseContext ctx)
    {
        try
        {
            // StatisticMapWrapper contains GV keys; we want Priority keys
            StatisticMapWrapper map = getStatsBean(ctx).getAllFilterBy(customField);
            transformStatisticMapWrapper(map);
            return map;
        }
        catch (SearchException e)
        {
            log.error("Could not search for custom in project '" + ctx.getProject().getKey() + "'", e);
        }
        
        return null;
    }

    void addSearchSorts(final JqlQueryBuilder builder)
    {
        // for the Priority fragment, we want Priority first then Key
        builder.orderBy().issueKey(SortOrder.DESC, true);
    }

    private void transformStatisticMapWrapper(final StatisticMapWrapper map)
    {
        Map<Option, Integer> customMap = new LinkedHashMap<Option, Integer>(map.size());
        for (Object o : map.entrySet())
        {
            Map.Entry entry = (Map.Entry) o;
            Option custom = (Option) entry.getKey();
            customMap.put(custom, (Integer) entry.getValue());

        }
        map.setStatistics(customMap); 
    }

    static public class OptionUrlUtil extends AbstractFilterUrlFragmentUtil<Option>
    {
        public OptionUrlUtil(final SearchRequest searchRequest, final User user, final ApplicationProperties applicationProperties, VelocityRequestContextFactory velocityContextFactory, SearchService searchService)
        {
           super(searchRequest, user, velocityContextFactory, applicationProperties, searchService);
        }

        protected Clause getDomainClause(final Option option)
        {
            JqlClauseBuilder builder = JqlQueryBuilder.newClauseBuilder();
            builder.customField((long) 10000).eq(option.getValue());
            return builder.buildClause();
        }

        protected OrderBy getOrderBy()
        {
            JqlOrderByBuilder jqlOrderByBuilder = JqlQueryBuilder.newOrderByBuilder();
            jqlOrderByBuilder.priority(SortOrder.DESC);
            return jqlOrderByBuilder.buildOrderBy();
        }


    }

}